package com.axxc.cloud.aspect;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSONObject;
import com.axxc.cloud.annotation.Owner;
import com.axxc.cloud.annotation.SystemOperationLog;
import com.axxc.cloud.enums.ExecuteMethodType;
import com.axxc.cloud.mapper.IBaseServiceOwnerMapper;
import com.axxc.cloud.mapper.IBaseSystemExecuteLogEntityMapper;
import com.axxc.cloud.model.BaseServiceOwnerEntity;
import com.axxc.cloud.model.BaseSystemExecuteLogEntity;

@Aspect // 定义为切面
@Component // 纳入容器管理
public class SelfDefinitionAspect {

	private Logger logger = LoggerFactory.getLogger(getClass());

	private static final ExecutorService threadPool = Executors.newFixedThreadPool(5);

	@Autowired
	private IBaseSystemExecuteLogEntityMapper baseSystemOperationLogEntityMapper;
	@Autowired
	private IBaseServiceOwnerMapper baseServiceOwnerMappe;

	// @Pointcut("@annotation(com.axxc.jpa.annotation.MyLog)") // 切入点为标记该注解的地方
	// @Pointcut("execution(* com.axxc.*.web..*.*(..))") // SPEL表达式.拦截指定方法,可复用

	// 使用环绕通知
	@Around("@annotation(com.axxc.cloud.annotation.SystemOperationLog)") // 拦截标记注解的地方
	public Object before(ProceedingJoinPoint pjp) throws Throwable {

		// 接收到请求，记录请求内容
		BaseSystemExecuteLogEntity logEntity = executeAroundAop(pjp);

		// TODO 前置操作
		insertExecuteLog(logEntity);

		long start = System.currentTimeMillis();
		Object value = pjp.proceed();
		long end = System.currentTimeMillis();

		// TODO 后置操作,修改执行时间,
		updateExecuteLog(logEntity, start, end);

		return value;
	}

	private void updateExecuteLog(BaseSystemExecuteLogEntity logEntity, long start, long end) {
		try {
			Runnable task = new Runnable() {
				@Override
				public void run() {
					updateExecuteLogTime(logEntity, start, end);
				}
			};
			threadPool.submit(task);
		} catch (Exception e) {
			logger.warn(this.getClass() + "执行修改异常 ", e);
		}
	}

	private void insertExecuteLog(BaseSystemExecuteLogEntity logEntity) {
		try {
			// 插入拦截日志

			int count = countExecuteCount(logEntity);
			logEntity.setExecuteCount(count + 1);
			baseSystemOperationLogEntityMapper.insertSelective(logEntity);
		} catch (Exception e) {
			logger.warn(this.getClass() + "插入拦截日志异常 ", e);
		}
	}

	private BaseSystemExecuteLogEntity executeAroundAop(ProceedingJoinPoint pjp) {
		BaseSystemExecuteLogEntity logEntity = new BaseSystemExecuteLogEntity();
		try {
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
					.currentRequestAttributes();
			HttpServletRequest request = attributes.getRequest();
			MethodSignature signature = (MethodSignature) pjp.getSignature();// 因为在方法级别上使用,强转
			Method method = signature.getMethod();
			logger.info("【前置通知】the method 【" + method.getName() + "】 begins with " + JSONObject.toJSON(pjp.getArgs()));

			SystemOperationLog systemOperationLog = method.getAnnotation(SystemOperationLog.class);
			// 存在该日志拦截操作注解
			if (systemOperationLog != null) {

				Integer ownerGroupId = getOwnerGroupId(systemOperationLog);
				logEntity.setOwnerGroupId(ownerGroupId);
				ExecuteMethodType methodType = systemOperationLog.executeMethodType();
				logEntity.setExecuteMethodType(methodType.name());
				for (ExecuteMethodType type : ExecuteMethodType.values()) {
					// 比较枚举索引值,从0开始
					if (methodType.ordinal() == type.ordinal()) {
						System.out.println(type.getTypeInfo());
						switch (type) {
						case CREATE:

							break;
						case READ:

							break;
						case UPDATE:

							break;
						case DELETE:

							break;
						default:
							break;
						}
					}
				}
				logEntity.setExecuteMethodArgs(JSONObject.toJSONString(pjp.getArgs()));
				logEntity.setExecuteMethodArgsNumber(pjp.getArgs().length);
				// 来访Ip
				logEntity.setClientIp(request.getRemoteAddr());
				// 本机Ip
				logEntity.setServiceIp(request.getLocalAddr());
				logEntity.setExecuteDateBaseName(systemOperationLog.dataBaseName());
				logEntity.setExecuteMethodName(method.getName());
				logEntity.setExecuteTableName(systemOperationLog.tableName());
				logEntity.setCreateTime(new Date());
				logEntity.setExecuteClassName(method.getClass().getName());
				logEntity.setExecuteStatus(1);// 成功
				// 保存操作日志
				logger.info("操作日志 :{}", JSONObject.toJSONString(logEntity));

			}
		} catch (Exception e) {
			logEntity.setExecuteStatus(0);// 失败
			logEntity.setExecuteErrorClassName(e.getClass().toString().split(" ")[1]);
			logEntity.setExecuteErrorMsg(e.getMessage());
			logger.warn(this.getClass() + "\t拦截执行异常", e);
		}
		return logEntity;
	}

	private void updateExecuteLogTime(BaseSystemExecuteLogEntity logEntity, long start, long end) {
		Integer primaryKey = logEntity.getId();
		logEntity = new BaseSystemExecuteLogEntity();
		logEntity.setId(primaryKey);
		logEntity.setExecuteTime(Long.valueOf((end - start) * 1L).intValue());
		this.baseSystemOperationLogEntityMapper.updateByPrimaryKeySelective(logEntity);
	}

	private int countExecuteCount(BaseSystemExecuteLogEntity logEntity) {
		BaseSystemExecuteLogEntity e = new BaseSystemExecuteLogEntity();
		e.setExecuteDateBaseName(logEntity.getExecuteDateBaseName());
		e.setExecuteTableName(logEntity.getExecuteTableName());
		e.setExecuteClassName(logEntity.getExecuteClassName());
		e.setExecuteMethodType(logEntity.getExecuteMethodType());
		e.setExecuteMethodName(logEntity.getExecuteMethodName());
		e.setExecuteMethodArgsNumber(logEntity.getExecuteMethodArgsNumber());
		return this.baseSystemOperationLogEntityMapper.selectCount(e);
	}

	private Integer getOwnerGroupId(SystemOperationLog systemOperationLog) {

		String groupName = systemOperationLog.ownerGroupName();
		BaseServiceOwnerEntity record = new BaseServiceOwnerEntity();
		record.setName(groupName);
		BaseServiceOwnerEntity ownerEntity = this.baseServiceOwnerMappe.selectOne(record);
		if (ownerEntity == null) {
			BaseServiceOwnerEntity e = new BaseServiceOwnerEntity();
			e.setName(groupName);
			e.setCreateTime(new Date());
			e.setParentId(0);
			// 新增
			this.baseServiceOwnerMappe.insertSelective(e);
			ownerEntity = e;
		}
		// 保存组内维护人员
		insertChildrenOwners(systemOperationLog.owners(), ownerEntity.getId());
		return ownerEntity.getId();
	}

	private void insertChildrenOwners(Owner[] owners, Integer parentId) {
		for (Owner owner : owners) {
			BaseServiceOwnerEntity record = new BaseServiceOwnerEntity();
			record.setName(owner.ownerName());
			record.setParentId(parentId);
			// TODO 此处会设置长拼,短拼的值,注意
			BaseServiceOwnerEntity ownerEntity = this.baseServiceOwnerMappe.selectOne(record);

			if (ownerEntity == null) {
				record.setParentId(parentId);
				record.setCreateTime(new Date());
				record.setContactWay(owner.ownerContactWay());
				this.baseServiceOwnerMappe.insertSelective(record);
			} else {
				// 存在,但联系方式不同,修改
				if (!owner.ownerContactWay().equalsIgnoreCase(ownerEntity.getContactWay())) {
					record = new BaseServiceOwnerEntity();
					record.setContactWay(owner.ownerContactWay());
					record.setId(ownerEntity.getId());
					this.baseServiceOwnerMappe.updateByPrimaryKeySelective(record);
				}
			}
		}

	}

}
